package cadtoolbox.graphical;

import edu.uci.ics.jung.algorithms.layout.FRLayout;
import edu.uci.ics.jung.algorithms.layout.Layout;
import edu.uci.ics.jung.visualization.decorators.ToStringLabeller;

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeListener;
import java.util.LinkedHashSet;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JSeparator;
import javax.swing.KeyStroke;
import javax.swing.border.LineBorder;
import java.util.Iterator;

import org.apache.commons.collections15.Factory;

import cadtoolbox.model.SequenceVertex;
import cadtoolbox.model.OligoGraph;

public class MainFrame extends JFrame {
	
	private OligoGraph<SequenceVertex,String> graph;
	
	
	
	public MainFrame(){
		super("CADToolbox");
		initGraph();
		initComponents();
		this.addWindowListener(new java.awt.event.WindowListener(){

			@Override
			public void windowActivated(WindowEvent arg0) {
				// TODO Auto-generated method stub
				
			}

			@Override
			public void windowClosed(WindowEvent arg0) {
				
			}

			@Override
			public void windowClosing(WindowEvent arg0) {
				if(!graph.saved){
					int ret = JOptionPane.showConfirmDialog(null, "Graph is not saved. Close?", "Warning", JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE);
					if(ret == JOptionPane.CANCEL_OPTION){
						return;
					}
				}
				System.exit(0);
			}

			@Override
			public void windowDeactivated(WindowEvent arg0) {
				// TODO Auto-generated method stub
				
			}

			@Override
			public void windowDeiconified(WindowEvent arg0) {
				// TODO Auto-generated method stub
				
			}

			@Override
			public void windowIconified(WindowEvent arg0) {
				// TODO Auto-generated method stub
				
			}

			@Override
			public void windowOpened(WindowEvent arg0) {
				// TODO Auto-generated method stub
				
			}
			
		});
	}
	
	private void initGraph(){
		final OligoGraph<SequenceVertex, String> g = new OligoGraph<SequenceVertex,String>();
	    g.initFactories(new VertexFactory<SequenceVertex>(g){
	    	
			public SequenceVertex create() {
				SequenceVertex newvertex = associatedGraph.popAvailableVertex();
				if (newvertex == null){
					newvertex = new SequenceVertex(associatedGraph.getVertexCount() + 1);
				} else {
					newvertex = new SequenceVertex(newvertex.ID);
				}
				return newvertex;
			}

			@Override
			public SequenceVertex copy(SequenceVertex original) {
				 SequenceVertex ret = new SequenceVertex(original.ID);
				 ret.inputs = original.inputs;
				 return ret;
			} 	
	    }, new EdgeFactory<SequenceVertex,String>(g){
	    	public String createEdge(SequenceVertex v1, SequenceVertex v2){
	    		return v1.ID+"->"+v2.ID;
	    	}
	    	public String inhibitorName(String s){
	    		return "Inhib"+s;
	    	}
	    });
	    this.graph = g;
	}
	
	private void initComponents(){
		final DataPanel<String> dataPanel = new DataPanel<String>(graph);
		JMenuBar jMenuBar = new javax.swing.JMenuBar();
        JMenu jMenuFile = new javax.swing.JMenu();
        JMenuItem jMenuItemNew = new javax.swing.JMenuItem();
        JMenuItem jMenuItemOpen = new javax.swing.JMenuItem();
        JMenuItem jMenuItemSave = new javax.swing.JMenuItem();
        JMenuItem jMenuItemSaveAs = new javax.swing.JMenuItem();
        JMenuItem jMenuItemUndo = new javax.swing.JMenuItem();
        JSeparator jSeparator = new javax.swing.JPopupMenu.Separator();
        JMenuItem jMenuItemExport = new javax.swing.JMenuItem();
        JMenu jMenuSequences = new javax.swing.JMenu();
        JMenuItem jMenuItemNewSeq = new javax.swing.JMenuItem();
        JMenuItem jMenuItemFusion = new javax.swing.JMenuItem();
        JMenuItem jMenuItemDuplicate = new javax.swing.JMenuItem();
        JMenuItem jMenuItemImport = new javax.swing.JMenuItem();
        JMenuItem jMenuOptions = new javax.swing.JMenuItem();
        //JMenu jMenuPlotMenu = new javax.swing.JMenu();
        JMenuItem jMenuPlot = new javax.swing.JMenuItem();
        //JMenuItem jMenuPlotRange = new javax.swing.JMenuItem();
        JMenuItem jMenuImportInput = new javax.swing.JMenuItem();
        
        GraphicInterfaceMouseAdapter myadapter = new GraphicInterfaceMouseAdapter();
        
        Layout<SequenceVertex, String> frlayout = new FRLayout(graph);
        frlayout.setSize(new Dimension(300,300)); // sets the initial size of the space
         // The BasicVisualizationServer<V,E> is parameterized by the edge types
         MyVisualizationServer<SequenceVertex,String> vv = 
                  new MyVisualizationServer<SequenceVertex,String>(frlayout, myadapter,dataPanel);
         vv.setRenderer(new OligoRenderer<SequenceVertex,String>());
         vv.setBorder(LineBorder.createBlackLineBorder());
         vv.addMouseListener(myadapter);
         vv.addMouseMotionListener(myadapter);
         vv.getRenderContext().setVertexFillPaintTransformer(new MyVertexFillPaintTransformer(graph));
         vv.getRenderContext().setVertexLabelTransformer(new ToStringLabeller<SequenceVertex>());
         
         
         
         MyActionlistener<SequenceVertex,String> listen = new MyActionlistener<SequenceVertex,String>(frlayout,dataPanel);
         //TODO: add all the action listening here
         jMenuItemNew.setActionCommand("new");
         jMenuItemNew.addActionListener(listen);
         
         jMenuItemOpen.setActionCommand("open");
         jMenuItemOpen.addActionListener(listen);
         
         jMenuItemSave.setActionCommand("save");
         jMenuItemSave.addActionListener(listen);
         
         jMenuItemSaveAs.setActionCommand("saveas");
         jMenuItemSaveAs.addActionListener(listen);
         
         jMenuItemUndo.setActionCommand("undo");
         jMenuItemUndo.addActionListener(listen);
         
         jMenuItemExport.setActionCommand("export");
         jMenuItemExport.addActionListener(listen);
         
         jMenuItemNewSeq.setActionCommand("newseq");
         jMenuItemNewSeq.addActionListener(listen);
         
         jMenuItemFusion.setActionCommand("fusion");
         jMenuItemFusion.addActionListener(listen);
         
         jMenuItemDuplicate.setActionCommand("duplicate");
         jMenuItemDuplicate.addActionListener(listen);
         
         jMenuItemImport.setActionCommand("import");
         jMenuItemImport.addActionListener(listen);
         
         jMenuImportInput.setActionCommand("impInput");
         jMenuImportInput.addActionListener(listen);
         
         jMenuOptions.setActionCommand("options");
         jMenuOptions.addActionListener(listen);
         
         jMenuPlot.setActionCommand("plot");
         jMenuPlot.addActionListener(listen);
         
         //jMenuPlotRange.setActionCommand("plotrange");
         //jMenuPlotRange.addActionListener(listen);
         
         setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
         
         jMenuBar.setBackground(new java.awt.Color(204, 199, 196));
         jMenuOptions.setBackground(new java.awt.Color(204, 199, 196));
         jMenuPlot.setBackground(new java.awt.Color(204, 199, 196));

         jMenuFile.setText("File");

         jMenuItemNew.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_N, java.awt.event.InputEvent.CTRL_MASK));
         jMenuItemNew.setText("New");
         
        
         jMenuFile.add(jMenuItemNew);

         jMenuItemOpen.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_O, java.awt.event.InputEvent.CTRL_MASK));
         jMenuItemOpen.setText("Open");
         jMenuFile.add(jMenuItemOpen);

         jMenuItemSave.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_S, java.awt.event.InputEvent.CTRL_MASK));
         jMenuItemSave.setText("Save");
         jMenuFile.add(jMenuItemSave);
         
         jMenuItemSaveAs.setText("Save as");
         jMenuFile.add(jMenuItemSaveAs);

         jMenuItemUndo.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_Z, java.awt.event.InputEvent.CTRL_MASK));
         jMenuItemUndo.setText("Undo");
         jMenuFile.add(jMenuItemUndo);
         
         jSeparator.setBackground(new java.awt.Color(236, 151, 66));
         jSeparator.setForeground(new java.awt.Color(186, 94, 94));
         jMenuFile.add(jSeparator);

         jMenuItemExport.setText("Export");
         jMenuFile.add(jMenuItemExport);

         jMenuBar.add(jMenuFile);

         jMenuSequences.setText("Sequences");

         jMenuItemNewSeq.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_A, java.awt.event.InputEvent.CTRL_MASK));
         jMenuItemNewSeq.setText("New sequence");
         jMenuSequences.add(jMenuItemNewSeq);

         jMenuItemFusion.setText("Join selected");
         jMenuSequences.add(jMenuItemFusion);

         jMenuItemDuplicate.setText("Duplicate selected");
         jMenuSequences.add(jMenuItemDuplicate);

         jMenuItemImport.setText("Import module");
         jMenuSequences.add(jMenuItemImport);

         jMenuImportInput.setText("Import input");
         jMenuSequences.add(jMenuImportInput);
         
         jMenuBar.add(jMenuSequences);

         jMenuOptions.setText("Options");
         

         //jMenuPlotMenu.setText("Plot");
         jMenuPlot.setText("Plot");
         jMenuPlot.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_P, java.awt.event.InputEvent.CTRL_MASK));
         //jMenuPlotRange.setText("Range");
         //jMenuPlotMenu.add(jMenuPlot);
         //jMenuPlotMenu.add(jMenuPlotRange);
         jMenuBar.add(jMenuOptions);
         jMenuBar.add(jMenuPlot);   
         
         
         setJMenuBar(jMenuBar);

         javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
         getContentPane().setLayout(layout);
         layout.setHorizontalGroup(
             layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
             .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                 .addContainerGap()
                 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                     .addComponent(dataPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                     .addComponent(vv))
                 .addContainerGap())
         );
         layout.setVerticalGroup(
             layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
             .addGroup(layout.createSequentialGroup()
                 .addContainerGap()
                 .addComponent(vv, 0,300,Short.MAX_VALUE)
                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                 .addComponent(dataPanel, 150, 150, 180)
                 .addContainerGap())
         );
         
         //Other actions
         final OligoGraph<SequenceVertex,String> g = this.graph;
         this.rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE,0),
         "escaped");
         this.rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE,0),
         "delete");
         
         this.rootPane.getActionMap().put("escaped",
                 new AbstractAction(){

					@Override
					public void actionPerformed(ActionEvent arg0) {

						g.getSelected().clear();
						dataPanel.update();
						repaint();
					}
        	 
         });
         this.rootPane.getActionMap().put("delete",
                 new AbstractAction(){

					@Override
					public void actionPerformed(ActionEvent arg0) {
						Iterator<SequenceVertex> it = g.getSelected().iterator();
						while(it.hasNext()){
							SequenceVertex s = it.next();
							if(g.getVertices().contains(s))
								g.removeVertex(s);
						}
						g.getSelected().clear();
						dataPanel.update();
						repaint();
					}
        	 
         });

         pack();
	}
	
	public static void main(String[] args){
		MainFrame myframe = new MainFrame();
		myframe.setVisible(true);
	}
}
